#include "ScreenMask.h"


ScreenMask::ScreenMask(bool ab_Virtual)
{
	mb_Virtual = ab_Virtual;

	screenMaskVB=NULL;
	screenMaskIB=NULL;
	ScreenCoords=false;
	mb_Changed = true;
	this->SetBias(true);
	z = 0.0f;

	vertex.push_back(ScreenMaskVertex());
	vertex.push_back(ScreenMaskVertex());
	vertex.push_back(ScreenMaskVertex());
	vertex.push_back(ScreenMaskVertex());
}


ScreenMask::~ScreenMask()
{
	Remove();
}



void ScreenMask::SetZ(float inz)
{
	z=inz;
}


void ScreenMask::SetBias(bool ab_State)
{
	mb_Bias = ab_State;
	mb_Changed = true;
}


void ScreenMask::SetSize(float inw, float inh)
{
	width=inw;
	height=inh;
	mb_Changed = true;
}


void ScreenMask::SetPos(float inx, float iny)
{
	x=inx;
	y=iny;
	mb_Changed = true;
}


void ScreenMask::SetTextureCoords(float a, float b, float c, float d, int channel)
{
	vertex[0].UV[channel].x=a;
	vertex[0].UV[channel].y=b;

	vertex[1].UV[channel].x=c;
	vertex[1].UV[channel].y=b;

	vertex[2].UV[channel].x=c;
	vertex[2].UV[channel].y=d;

	vertex[3].UV[channel].x=a;
	vertex[3].UV[channel].y=d;
	mb_Changed = true;
}


void ScreenMask::SetFrame(int x, int y, int maxX, int maxY, int channel)
{
	float x1 = x/float(maxX);
	float x2 = x1+1/float(maxX);
	float y1 = y/float(maxY);
	float y2 = y1+1/float(maxY);

	SetTextureCoords(x1,y1,x2,y1,channel);
}


void ScreenMask::BeginRender(IDirect3DDevice9* lpd3dd)
{
	if (mb_Changed)
		this->ReCreate(lpd3dd);

	if (mb_Virtual)
		return;

	lpd3dd->SetFVF(D3DFVF_SCREENMASK);
	lpd3dd->SetIndices( screenMaskIB );
	lpd3dd->SetStreamSource( 0, screenMaskVB, 0, sizeof(ScreenMask::TScreenMaskVertex) );
}


void ScreenMask::Render(IDirect3DDevice9* lpd3dd)
{
	if (mb_Virtual)
		return;

	lpd3dd->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, (UINT)vertex.size(), 0, (UINT)vertex.size()/4*2);	
}


void ScreenMask::Remove()
{
	if (mb_Virtual)
		return;

	if(screenMaskIB)
	{
		screenMaskIB->Release();
		screenMaskIB=NULL;
	}
	if(screenMaskVB)
	{
		screenMaskVB->Release();
		screenMaskVB=NULL;
	}
}


void ScreenMask::Create(IDirect3DDevice9* lpd3dd,float inx,float iny,float inwidth, float inheight, bool useScreenCoords)
{
	ScreenCoords = useScreenCoords;

	x=inx;
	y=iny;
	width=inwidth;
	height=inheight;

	for(int i=0; i<1; i++)
		SetTextureCoords(0,0,1,1,i);
	
	if (!mb_Virtual)
	{
		//insert this to a vertexbuffer
		lpd3dd->CreateVertexBuffer( (UINT)(sizeof(ScreenMask::TScreenMaskVertex)*vertex.size()),
										D3DUSAGE_WRITEONLY, D3DFVF_SCREENMASK, D3DPOOL_MANAGED,
										&screenMaskVB, NULL );

		//and create a indexbuffer
		lpd3dd->CreateIndexBuffer( (UINT)((vertex.size()/4)*6 * sizeof(WORD)),
										D3DUSAGE_WRITEONLY,
										D3DFMT_INDEX16, D3DPOOL_MANAGED,
										&screenMaskIB, NULL );

		LPWORD lpIndi;
		screenMaskIB->Lock( 0, 0, (void**)&lpIndi, 0 );

		for (unsigned int i=0; i<vertex.size()/4; ++i)
		{
			lpIndi[i*6+0]=i*4+0;
			lpIndi[i*6+1]=i*4+1;
			lpIndi[i*6+2]=i*4+2;
			lpIndi[i*6+3]=i*4+2;
			lpIndi[i*6+4]=i*4+3;
			lpIndi[i*6+5]=i*4+0;
		}
		
		screenMaskIB->Unlock();
	}

	ReCreate(lpd3dd);
}


void ScreenMask::ReCreate(IDirect3DDevice9* lpd3dd)
{
	float lf_Bias = 0.0f;
	if (mb_Bias)
		lf_Bias = 0.5f;
	if(ScreenCoords)
	{
		vertex[0].pos.x=x-lf_Bias;
		vertex[0].pos.y=y-lf_Bias;
		vertex[0].pos.z=z;

		vertex[1].pos.x=width-lf_Bias;
		vertex[1].pos.y=y-lf_Bias;
		vertex[1].pos.z=z;

		vertex[2].pos.x=width-lf_Bias;
		vertex[2].pos.y=height-lf_Bias;
		vertex[2].pos.z=z;

		vertex[3].pos.x=x-lf_Bias;
		vertex[3].pos.y=height-lf_Bias;
		vertex[3].pos.z=z;
	}
	else
	{
		D3DVIEWPORT9 Mode;
		lpd3dd->GetViewport(&Mode);
		float xx = Mode.Width*width;
		float yy = Mode.Height*height;
		float x1 = Mode.Width*x;
		float y1 = Mode.Height*y;

		vertex[0].pos.x=float(x1)-lf_Bias;
		vertex[0].pos.y=float(y1)-lf_Bias;
		vertex[0].pos.z=z;

		vertex[1].pos.x=float(x1+xx)-lf_Bias;
		vertex[1].pos.y=float(y1)-lf_Bias;
		vertex[1].pos.z=z;

		vertex[2].pos.x=float(x1+xx)-lf_Bias;
		vertex[2].pos.y=float(y1+yy)-lf_Bias;
		vertex[2].pos.z=z;

		vertex[3].pos.x=float(x1)-lf_Bias;
		vertex[3].pos.y=float(y1+yy)-lf_Bias;
		vertex[3].pos.z=z;
	}

	if (!mb_Virtual)
	{
		ScreenMask::TScreenMaskVertex* pvVertices;
		screenMaskVB->Lock( 0, 0, (void**)&pvVertices, 0 );
		for( DWORD i=0; i<vertex.size(); i++ )
			pvVertices[i] = vertex[i];
		screenMaskVB->Unlock();
	}

	mb_Changed = false;
}


std::vector<ScreenMask::TScreenMaskVertex> ScreenMask::get_VertexList()
{
	return vertex;
}

////////////////////////////////

BatchScreenMask::BatchScreenMask(IDirect3DDevice9* lpd3dd, int ai_MaxVertex)
{
	mi_MaxVerticies = ai_MaxVertex;

	//insert this to a vertexbuffer
	lpd3dd->CreateVertexBuffer( (UINT)(sizeof(ScreenMask::TScreenMaskVertex)*ai_MaxVertex),
									D3DUSAGE_WRITEONLY, D3DFVF_SCREENMASK, D3DPOOL_MANAGED,
									&screenMaskVB, NULL );

	//and create a indexbuffer
	lpd3dd->CreateIndexBuffer( (UINT)((ai_MaxVertex/4)*6 * sizeof(WORD)),
									D3DUSAGE_WRITEONLY,
									D3DFMT_INDEX16, D3DPOOL_MANAGED,
									&screenMaskIB, NULL );

	LPWORD lpIndi;
	screenMaskIB->Lock( 0, 0, (void**)&lpIndi, 0 );

	for (unsigned int i=0; i < static_cast<unsigned int>(ai_MaxVertex / 4); ++i)
	{
		lpIndi[i*6+0]=i*4+0;
		lpIndi[i*6+1]=i*4+1;
		lpIndi[i*6+2]=i*4+2;
		lpIndi[i*6+3]=i*4+2;
		lpIndi[i*6+4]=i*4+3;
		lpIndi[i*6+5]=i*4+0;
	}
	
	screenMaskIB->Unlock();
}


BatchScreenMask::~BatchScreenMask()
{
	// free old data
	if(screenMaskIB)
	{
		screenMaskIB->Release();
		screenMaskIB=NULL;
	}
	if(screenMaskVB)
	{
		screenMaskVB->Release();
		screenMaskVB=NULL;
	}
}


void BatchScreenMask::BeginRender(IDirect3DDevice9* lpd3dd)
{
	if (vertex.size() > 0)
	{
		lpd3dd->SetFVF(D3DFVF_SCREENMASK);
		lpd3dd->SetIndices( screenMaskIB );
		lpd3dd->SetStreamSource( 0, screenMaskVB, 0, sizeof(ScreenMask::TScreenMaskVertex) );
	}
}


void BatchScreenMask::Render(IDirect3DDevice9* lpd3dd)
{
	if (vertex.size() > 0)
		lpd3dd->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, (UINT)vertex.size(), 0, (UINT)(vertex.size()/4*2));
}


void BatchScreenMask::AddScreenMaskData(ScreenMask& ar_ScreenMask, IDirect3DDevice9* lpd3dd, bool ab_ResetFirst, bool ab_AllowRebuild)
{
	if (ab_ResetFirst)
		vertex.clear();

	std::vector<ScreenMask::TScreenMaskVertex> addvertex = ar_ScreenMask.get_VertexList();
	for (unsigned int i=0; i<addvertex.size() && vertex.size() <= (UINT)mi_MaxVerticies; ++i)
		vertex.push_back(addvertex[i]);

	if (!ab_AllowRebuild)
		return;

	ScreenMask::TScreenMaskVertex* pvVertices;
	screenMaskVB->Lock( 0, 0, (void**)&pvVertices, 0 );
	for( DWORD i=0; i<vertex.size(); i++ )
		pvVertices[i] = vertex[i];
	screenMaskVB->Unlock();
}
